package com.game.data {
	import com.game.ammo.AmmoGraphics;
	import com.game.events.GameEvent;
	import com.game.utils.TowerType;
	
	import flash.display.BitmapData;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.filters.ColorMatrixFilter;
	import flash.filters.DropShadowFilter;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.media.Sound;
	import flash.text.Font;
	import flash.utils.getDefinitionByName;
	public class Data extends EventDispatcher {
		public static const STEP:int = 50;
		public static const INFLATION:Number = 0.75;
		public static const GRAY_SCALE:ColorMatrixFilter = new ColorMatrixFilter([0.33, 0.33, 0.33, 0, 00, 0.33, 0.33, 0.33, 0, 00, 0.33, 0.33, 0.33, 0, 00, 0, 0, 0, 1, 0]);
		public static const ICON_SIZE:int = 70;
		public static const SPEED_RESTORE_COUNTER:int = 40;
		public static const ENEMY_RELEASE_DELAY:int = 40*3;
		public static const IMAGE_PADDING:Number = 10;
		public static const LEVEL:Array=[
			[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
			[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
			[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
			[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
			[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
			[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
			[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
			[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
			[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]];
		private static var _goneFreeCounter:int = 20;
		private static var _mainFont:Font;
		private static var instance:Data;
		private static var _waveData:Array;
		private static var _stageHeight:int;
		private static var _stageWidth:int;
		private static var _assets:MovieClip;
		private static var _myPoints:int = 80*100;
		private static var _currentWave:Array;
		private static var _towerData:TowerInitObject;
		private static var _mapTexture:BitmapData;
		private static var _towerIdToUpgrade:int;
		private static var _towerIdToRemove:int;
		private static var _myLevel:Array;
		private static var _isPaused:Boolean;
		private static var _waveCounter:int = 0;
		private static var _soundAdd:int = 0;
		private static var _volume:Boolean=true;
		private static var _iniTilePoint:Point = new Point(0, 4);
		private static var _finTilePoint:Point = new Point(15, 4);
		/**
		 *  point to check tower location at.
		 */
		private static var _checkTowerAtPoint:Point;
		private static var _selectedTowerData:SelectedTowerObject;
		private static var _weapons:Vector.<WeaponsObject>;
		private static var _explosion:Vector.<BitmapData>;
		private static var _iconArray:Vector.<BitmapData>;
		private static var _soundArray:Vector.<Sound> = new Vector.<Sound>();
		private static var _ammoAnimArray:Vector.<BitmapData> = new Vector.<BitmapData>();
		private static var _enemyAnimArray:Vector.<Vector.<BitmapData>> = new Vector.<Vector.<BitmapData>>();
		private static var _weaponAnimArray:Vector.<Vector.<BitmapData>> = new Vector.<Vector.<BitmapData>>();
		public static function getInstance():Data {
			if (instance == null) {
				instance = new Data(new SingletonBlocker());
			}
			return instance;
		}
		public function Data(p_key:SingletonBlocker):void {
			if (p_key == null) {
				throw new Error("Error: Instantiation failed: Use SingletonDemo.getInstance() instead of new.");
			}
		}
		public function get assets():MovieClip {
			return _assets;
		}
		public function set assets(value:MovieClip):void {
			_assets = value;
			initiate();
		}
		private static function initiate():void {
			var BigBang:Class = getDefinitionByName("BigBang") as Class;
			var MapTexture:Class = getDefinitionByName("MapTexture") as Class;
			//
			//
			createIconData();
			createEnemyAnimData();
			createWeaponAnimData();
			createAmmoAnimData();
			createSoundData();
			//
			var font:Class = getDefinitionByName("DirtyEgo") as Class;
			Font.registerFont(font);
			_mainFont = new font();
			//
			_myLevel = copyLevel();
			var bang:MovieClip = new BigBang();
			//weapons creation
			_weapons = new Vector.<WeaponsObject>();
			_weapons[0] = new WeaponsObject(TowerType.BULLET, 2, 20, 15);
			_weapons[1] = new WeaponsObject(TowerType.SLOW, 2, 40, 30);
			_weapons[2] = new WeaponsObject(TowerType.ROCKET, 3, 110, 60);
			_weapons[3] = new WeaponsObject(TowerType.FIRE, 2, 200, 180);
			_weapons[4] = new WeaponsObject(TowerType.SPARK, 2, 240, 200);
			_weapons[5] = new WeaponsObject(TowerType.WAVE, 2, 480, 400);
			_waveData = EnemyWaves.data;
			_mapTexture = new MapTexture();
			createExplosionData(bang);
		}
		public static function copyLevel():Array {
			var tmp:Array=[];
			for(var i:int=0;i<LEVEL.length;i++){
				tmp.push(LEVEL[i].concat());
			}
			return tmp;
		}
		private static function createSoundData():void {
			var Fire:Class = getDefinitionByName("Fire") as Class;
			var Rocket:Class = getDefinitionByName("Rocket") as Class;
			var Slow:Class = getDefinitionByName("Slow") as Class;
			var Bullet:Class = getDefinitionByName("Bullet") as Class;
			var Spark:Class = getDefinitionByName("Spark") as Class;
			var Wave:Class = getDefinitionByName("Wave") as Class;
			//var MainLoop:Class = getDefinitionByName("MainLoop") as Class;
			_soundArray[0] = new Bullet();
			_soundArray[1] = new Slow();
			_soundArray[2] = new Rocket();
			_soundArray[3] = new Fire();
			_soundArray[4] = new Spark();
			_soundArray[5] = new Wave();
			//_soundArray[6] = new MainLoop();
		}
		private static function createAmmoAnimData():void {
			var Flame:Class = getDefinitionByName("Flame") as Class;
			var Missile:Class = getDefinitionByName("Missile") as Class;
			_ammoAnimArray[0] = AmmoGraphics.bullet();
			_ammoAnimArray[1] = AmmoGraphics.slow();
			_ammoAnimArray[2] = AmmoGraphics.rocket(new Missile());
			_ammoAnimArray[3] = AmmoGraphics.flame(new Flame());
			_ammoAnimArray[4] = AmmoGraphics.spark();
			_ammoAnimArray[5] = AmmoGraphics.wave();
		}
		private static function createEnemyAnimData():void {
			//
			buildEnemyUnit(Vector.<String>(["Unit_0"]));
			buildEnemyUnit(Vector.<String>(["Unit_10", "Unit_11", "Unit_12", "Unit_13", "Unit_14", "Unit_15", "Unit_16", "Unit_17", "Unit_18", "Unit_19"]), false); //walker
			buildEnemyUnit(Vector.<String>(["Unit_2"]));
			
			buildEnemyUnit(Vector.<String>(["Unit_4"]));
			buildEnemyUnit(Vector.<String>(["Unit_1"])); //plane
			
			buildEnemyUnit(Vector.<String>(["Unit_3"]));
			
			buildEnemyUnit(Vector.<String>(["Unit_8"])); //tank
			buildEnemyUnit(Vector.<String>(["Unit_5", "Unit_6", "Unit_7"])); //hellicopter
			buildEnemyUnit(Vector.<String>(["Unit_9"])); //tank
			
			//
		}
		private static function buildEnemyUnit(unitClassName:Vector.<String>, dropShadow:Boolean = true):void {
			_enemyAnimArray.push(new Vector.<BitmapData>());
			for (var i:int = 0; i < unitClassName.length; i++) {
				var PlaneTexture:Class = getDefinitionByName(unitClassName[i]) as Class;
				var bmp:BitmapData = new BitmapData(STEP + IMAGE_PADDING, STEP + IMAGE_PADDING, true, 0);
				var pln:BitmapData = new PlaneTexture();
				var matrix:Matrix = new Matrix(STEP / pln.width, 0, 0, STEP / pln.height, IMAGE_PADDING / 2, -(STEP + IMAGE_PADDING) + IMAGE_PADDING / 2);
				matrix.rotate(Math.PI / 2);
				bmp.draw(pln, matrix);
				if (dropShadow) {
					bmp.applyFilter(bmp, bmp.rect, new Point(0, 0), new DropShadowFilter(0, 0, 0x0, 1, 8, 8, 1, 3));
				}
				_enemyAnimArray[_enemyAnimArray.length - 1][i] = bmp;
			}
		}
		private static function createWeaponAnimData():void {
			var Weapon:Class = getDefinitionByName("Weapon") as Class;
			var weapon:MovieClip = new Weapon();
			var length:int = weapon.totalFrames;
			var weaponLength:int = length / 3;
			var counter:int = 1;
			while (counter < length) {
				_weaponAnimArray.push(new Vector.<BitmapData>());
				for (var i:int = counter; i < counter + 3; i++) {
					weapon.gotoAndStop(i);
					var bmpData:BitmapData = new BitmapData(STEP + IMAGE_PADDING, STEP + IMAGE_PADDING, true, 0x0000ff)
					var perc:Number = STEP / weapon.width;
					var matrix:Matrix = new Matrix(perc, 0, 0, perc, IMAGE_PADDING / 2 - (STEP + IMAGE_PADDING), IMAGE_PADDING / 2 - (STEP + IMAGE_PADDING));
					matrix.rotate(Math.PI);
					bmpData.draw(weapon, matrix, null, null, null, true);
					bmpData.applyFilter(bmpData, bmpData.rect, new Point(0, 0), new DropShadowFilter(0, 0, 0x0, 1, 8, 8, 1, 3))
					_weaponAnimArray[_weaponAnimArray.length - 1][i - counter] = bmpData
				}
				counter += 3;
			}
		}
		private static function createIconData():void {
			_iconArray = new Vector.<BitmapData>();
			for (var i:int = 1; i <= 15; i++) {
				var Icon:Class = getDefinitionByName("Icon" + i) as Class;
				_iconArray.push(new Icon());
				//
				var bmpData:BitmapData = new BitmapData(ICON_SIZE, ICON_SIZE, true, 0x0000ff)
				var perc:Number = ICON_SIZE / _iconArray[_iconArray.length - 1].width;
				bmpData.draw(_iconArray[_iconArray.length - 1], new Matrix(perc, 0, 0, perc), null, null, null, true);
				_iconArray[_iconArray.length - 1] = bmpData;
			}
		}
		private static function createExplosionData(bang:MovieClip):void {
			_explosion = new Vector.<BitmapData>();
			for (var f:int = 1; f <= bang.totalFrames; f++) {
				var bd:BitmapData = new BitmapData(STEP, STEP, true, 0x00000000);
				bang.gotoAndStop(f);
				bd.draw(bang, new Matrix(STEP / bang.width, 0, 0, STEP / bang.width));
				bd.lock();
				_explosion.push(bd);
			}
		}
		public function get weapons():Vector.<WeaponsObject> {
			return _weapons;
		}
		public function set weapons(value:Vector.<WeaponsObject>):void {
			_weapons = value;
		}
		public function get weaponAnimArray():Vector.<Vector.<BitmapData>> {
			return _weaponAnimArray;
		}
		public function set weaponAnimArray(value:Vector.<Vector.<BitmapData>>):void {
			_weaponAnimArray = value;
		}
		public function get iconArray():Vector.<BitmapData> {
			return _iconArray;
		}
		public function set iconArray(value:Vector.<BitmapData>):void {
			_iconArray = value;
		}
		public function get selectedTowerData():SelectedTowerObject {
			return _selectedTowerData;
		}
		public function set selectedTowerData(value:SelectedTowerObject):void {
			_selectedTowerData = value;
			this.dispatchEvent(new Event(GameEvent.TOWER_DATA_SET))
		}
		public function get myPoints():int {
			return _myPoints;
		}
		public function set myPoints(value:int):void {
			_myPoints = value;
			this.dispatchEvent(new Event(GameEvent.POINTS_UPDATED));
		}
		public function get towerIdToUpgrade():int {
			return _towerIdToUpgrade;
		}
		public function set towerIdToUpgrade(value:int):void {
			_towerIdToUpgrade = value;
			this.dispatchEvent(new Event(GameEvent.TOWER_UPGRADE));
		}
		public function get towerIdToRemove():int {
			return _towerIdToRemove;
		}
		public function set towerIdToRemove(value:int):void {
			_towerIdToRemove = value;
			this.dispatchEvent(new Event(GameEvent.TOWER_REMOVE));
		}
		public function get myLevel():Array {
			return _myLevel;
		}
		public function set myLevel(value:Array):void {
			_myLevel = value;
		}
		public function get checkTowerAtPoint():Point {
			return _checkTowerAtPoint;
		}
		public function set checkTowerAtPoint(value:Point):void {
			_checkTowerAtPoint = value;
			this.dispatchEvent(new Event(GameEvent.GET_TOWER_AT_POINT));
		}
		public function get stageHeight():int {
			return _stageHeight;
		}
		public function set stageHeight(value:int):void {
			_stageHeight = value;
		}
		public function get stageWidth():int {
			return _stageWidth;
		}
		public function set stageWidth(value:int):void {
			_stageWidth = value;
		}
		public function get mainFont():Font {
			return _mainFont;
		}
		public function set mainFont(value:Font):void {
			_mainFont = value;
		}
		public function get explosion():Vector.<BitmapData> {
			return _explosion;
		}
		public function set explosion(value:Vector.<BitmapData>):void {
			_explosion = value;
		}
		public function get enemyAnimArray():Vector.<Vector.<BitmapData>> {
			return _enemyAnimArray;
		}
		public function set enemyAnimArray(value:Vector.<Vector.<BitmapData>>):void {
			_enemyAnimArray = value;
		}
		public function get mapTexture():BitmapData {
			return _mapTexture;
		}
		public function set mapTexture(value:BitmapData):void {
			_mapTexture = value;
		}
		public function get goneFreeCounter():int {
			return _goneFreeCounter;
		}
		public function set goneFreeCounter(value:int):void {
			_goneFreeCounter = value;
			this.dispatchEvent(new Event(GameEvent.GONE_FREE_UPDATED));
		}
		public function get waveCounter():int {
			return _waveCounter;
		}
		public function set waveCounter(value:int):void {
			_waveCounter = value;
			this.dispatchEvent(new Event(GameEvent.ROUNDS_UPDATED));
		}
		public function get iniTilePoint():Point {
			return _iniTilePoint;
		}
		public function set iniTilePoint(value:Point):void {
			_iniTilePoint = value;
		}
		public function get finTilePoint():Point {
			return _finTilePoint;
		}
		public function set finTilePoint(value:Point):void {
			_finTilePoint = value;
		}
		public function get towerData():TowerInitObject {
			return _towerData;
		}
		public function set towerData(value:TowerInitObject):void {
			_towerData = value;
			this.dispatchEvent(new GameEvent(GameEvent.TOWER_CREATE));
		}
		public function get isPaused():Boolean {
			return _isPaused;
		}
		public function set isPaused(value:Boolean):void {
			_isPaused = value;
		}
		public function get currentWave():Array {
			return _waveData[_waveCounter];
		}
		public function get ammoAnimArray():Vector.<BitmapData> {
			return _ammoAnimArray;
		}
		public function get soundArray():Vector.<Sound> {
			return _soundArray;
		}
		public function get soundAdd():int {
			return _soundAdd;
		}
		public function set soundAdd(value:int):void {
			_soundAdd = value;
			this.dispatchEvent(new GameEvent(GameEvent.SOUND_CREATE));
		}
		public  function get volume():Boolean{
			return _volume;
		}
		public  function set volume(value:Boolean):void{
			_volume = value;
		}

	}
}
internal class SingletonBlocker {
}